#include "frameData.h"

namespace eqPc
{

FrameData::FrameData()
		: _rotation( eq::Matrix4f::ZERO )
		, _modelRotation( eq::Matrix4f::ZERO )
		, _position( eq::Vector3f::ZERO )
		, _modelID( co::base::UUID::ZERO )
		, _renderMode( pc::RENDER_MODE_DISPLAY_LIST )
		, _colorMode( COLOR_MODEL )
		, _quality( 1.0f )
		, _ortho( false )
		, _statistics( false )
		, _help( false )
		, _wireframe( false )
		, _pilotMode( false )
		, _idle( false )
		, _compression( true )
		, _currentViewID( co::base::UUID::ZERO )
{
	reset();
	EQINFO << "New FrameData " << std::endl;
}

void FrameData::serialize( co::DataOStream& os, const uint64_t dirtyBits )
{
	co::Serializable::serialize( os, dirtyBits );
	if( dirtyBits & DIRTY_CAMERA )
		os << _position << _rotation << _modelRotation;
	if( dirtyBits & DIRTY_FLAGS )
		os << _modelID << _renderMode << _colorMode << _quality << _ortho
		   << _statistics << _help << _wireframe << _pilotMode << _idle
		   << _compression;
	if( dirtyBits & DIRTY_VIEW )
		os << _currentViewID;
	if( dirtyBits & DIRTY_MESSAGE )
		os << _message;
}

void FrameData::deserialize( co::DataIStream& is, const uint64_t dirtyBits )
{
	co::Serializable::deserialize( is, dirtyBits );
	if( dirtyBits & DIRTY_CAMERA )
		is >> _position >> _rotation >> _modelRotation;
	if( dirtyBits & DIRTY_FLAGS )
		is >> _modelID >> _renderMode >> _colorMode >> _quality >> _ortho
		   >> _statistics >> _help >> _wireframe >> _pilotMode >> _idle
		   >> _compression;
	if( dirtyBits & DIRTY_VIEW )
		is >> _currentViewID;
	if( dirtyBits & DIRTY_MESSAGE )
		is >> _message;
}

void FrameData::setModelID( const eq::uint128_t& id )
{
	if( _modelID == id )
		return;

	_modelID = id;
	setDirty( DIRTY_FLAGS );
}

void FrameData::setColorMode( const ColorMode mode )
{
	_colorMode = mode;
	setDirty( DIRTY_FLAGS );
}

void FrameData::setRenderMode( const pc::RenderMode mode )
{
	_renderMode = mode;
	setDirty( DIRTY_FLAGS );
}

void FrameData::setIdle( const bool idle )
{
	if( _idle == idle )
		return;

	_idle = idle;
	setDirty( DIRTY_FLAGS );
}

void FrameData::toggleOrtho()
{
	_ortho = !_ortho;
	setDirty( DIRTY_FLAGS );
}

void FrameData::toggleStatistics()
{
	_statistics = !_statistics;
	setDirty( DIRTY_FLAGS );
}

void FrameData::toggleHelp()
{
	_help = !_help;
	setDirty( DIRTY_FLAGS );
}

void FrameData::toggleWireframe()
{
	_wireframe = !_wireframe;
	setDirty( DIRTY_FLAGS );
}

void FrameData::toggleColorMode()
{
	_colorMode = static_cast< ColorMode >(( _colorMode + 1) % COLOR_ALL );
	setDirty( DIRTY_FLAGS );
}

void FrameData::adjustQuality( const float delta )
{
	_quality += delta;
	_quality = EQ_MAX( _quality, 0.1f );
	_quality = EQ_MIN( _quality, 1.0f );
	setDirty( DIRTY_FLAGS );
	EQINFO << "Set non-idle image quality to " << _quality << std::endl;
}

void FrameData::togglePilotMode()
{
	_pilotMode = !_pilotMode;
	setDirty( DIRTY_FLAGS );
}

void FrameData::toggleRenderMode()
{
	_renderMode = static_cast< pc::RenderMode >(
		( _renderMode + 1) % pc::RENDER_MODE_ALL );

	EQINFO << "Switched to " << _renderMode << std::endl;
	setDirty( DIRTY_FLAGS );
}

void FrameData::toggleCompression()
{
	_compression = !_compression;
	setDirty( DIRTY_FLAGS );
}

void FrameData::spinCamera( const float x, const float y )
{
	if( x == 0.f && y == 0.f )
		return;

	_rotation.pre_rotate_x( x );
	_rotation.pre_rotate_y( y );
	setDirty( DIRTY_CAMERA );
}

void FrameData::spinModel( const float x, const float y, const float z )
{
	if( x == 0.f && y == 0.f && z == 0.f )
		return;

	_modelRotation.pre_rotate_x( x );
	_modelRotation.pre_rotate_y( y );
	_modelRotation.pre_rotate_z( z );
	setDirty( DIRTY_CAMERA );
}

void FrameData::moveCamera( const float x, const float y, const float z )
{
	if( _pilotMode )
	{
		eq::Matrix4f matInverse;
		compute_inverse( _rotation, matInverse );
		eq::Vector4f shift = matInverse * eq::Vector4f( x, y, z, 1 );

		_position += shift;
	}
	else
	{
		_position.x() += x;
		_position.y() += y;
		_position.z() += z;
	}

	setDirty( DIRTY_CAMERA );
}

void FrameData::setCameraPosition( const eq::Vector3f& position )
{
	_position = position;
	setDirty( DIRTY_CAMERA );
}

void FrameData::setRotation( const eq::Vector3f& rotation )
{
	_rotation = eq::Matrix4f::IDENTITY;
	_rotation.rotate_x( rotation.x() );
	_rotation.rotate_y( rotation.y() );
	_rotation.rotate_z( rotation.z() );
	setDirty( DIRTY_CAMERA );
}

void FrameData::setModelRotation(  const eq::Vector3f& rotation )
{
	_modelRotation = eq::Matrix4f::IDENTITY;
	_modelRotation.rotate_x( rotation.x() );
	_modelRotation.rotate_y( rotation.y() );
	_modelRotation.rotate_z( rotation.z() );
	setDirty( DIRTY_CAMERA );
}

void FrameData::reset()
{


		_position   = eq::Vector3f::ZERO;
		//_position.z() = -2.f;
		
		_rotation      = eq::Matrix4f::IDENTITY;
		
		_modelRotation = eq::Matrix4f::IDENTITY;
		_modelRotation.rotate_x(-M_PI_2);
		//_modelRotation.rotate_z(-M_PI);
	setDirty( DIRTY_CAMERA );
}

void FrameData::setCurrentViewID( const eq::uint128_t& id )
{
	_currentViewID = id;
	setDirty( DIRTY_VIEW );
}

void FrameData::setMessage( const std::string& message )
{
	if( _message == message )
		return;

	_message = message;
	setDirty( DIRTY_MESSAGE );
}

}

